#include "execution.h"

void launch_execution(module* mdl, const int port) {
	int stock_restant=100;
	/*
	 * On va récupérer les informations dont l'action est concernée par l'ordre reçu
	 * On ouvre le fichier actions contenant la liste des actions
	 */
	FILE* actions = fopen("./data/actions", "r");
	if (actions==NULL) {
		printf("Erreur lors de l'ouverture du fichier d'actions");
		exit(1);
	}
	int nombre_actions=0;
	char temp[100];
	fseek(actions, 0, SEEK_SET);
	//récupération du nombre de lignes = nombre de commercants dans le fichier
	while (fgets(temp, 25, actions)!=0) {
		nombre_actions++;
	}

	int i;
	int j;
	action* act =( action*) malloc(sizeof(action));
	act->id = malloc (nombre_actions * sizeof(char*));
	act->val = malloc (nombre_actions * sizeof(char*));
	act->stock = malloc (nombre_actions * sizeof(char*));
	for(i=0;i<nombre_actions;i++) {
		act->id[i] = malloc (100 * sizeof(char));
		act->val[i] = malloc (100 * sizeof(char));
		act->stock[i] = malloc (100 * sizeof(char));
	}

	int curseur;
	fseek(actions, 0, SEEK_SET);
	//On repère la ligne dont l'action est concernée par l'ordre
	for(i=0;i<nombre_actions;i++) {
		fgets(temp, 25, actions);

		//on sépare l'id, la valeur et le stock de l'action
		j=0, curseur=0;
		while (temp[curseur]!='\0') {
			if (temp[curseur]==' ') {
				j++;
			} else {

				if (j==0)
				strncat(act->id[i], temp+curseur, 1);
				if (j==1)
				strncat(act->val[i], temp+curseur, 1);
				if (j==2)
				strncat(act->stock[i], temp+curseur, 1);
			}
			curseur++;
		}
	}
	fclose(actions);

	server srv = *(mdl->srv);
	strcpy(srv.name, mdl->name);
	srv.isAlive = 1;
	if ((srv.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}
	srv.local_addr.sin_family = AF_INET; /* host byte order */
	srv.local_addr.sin_port = htons(port); /* short, network byte order */
	srv.local_addr.sin_addr.s_addr = INADDR_ANY; /* auto-remplissage avec mon IP */
	bzero(&(srv.local_addr.sin_zero), 8); /* zero pour le reste de struct */

	if (bind(srv.sockfd,( struct sockaddr *)&(srv.local_addr),sizeof(struct sockaddr))== -1) {
		perror("bind");
		exit(1);
	}

	if (listen(srv.sockfd, 5) == -1) { // on choisit un nombre max de connexions = 5
		perror("listen");
		exit(1);
	}
	log_srv(&srv,"créé.");
	if(!fork()) { /* fils première génération - permet de revenir de la méthode par contre créé des zombies */
		while(1) { // boucle d' accept() pour recevoir les connexions
			srv.sin_size = sizeof(struct sockaddr_in);
			int new_fd; // descripteur lié au socket de la connexion courante
			if ((new_fd = accept(srv.sockfd, (struct sockaddr *)&(srv.remote_addr),
							&(srv.sin_size))) == -1) {
				perror("accept");
				continue;
			}
			if(!srv.isAlive) {
				close(new_fd); //si une connexion arrive alors que le programme est terminé, on sort
				break; return;
			}
			char tmp[128];
			sprintf(tmp, "connexion entrante depuis %s:%d",inet_ntoa(srv.remote_addr.sin_addr),srv.remote_addr.sin_port);
			log_srv(&srv,tmp);
			if (!fork()) { /* fils seconde génération - permet d'être multiclient */
				if(!srv.isAlive) {
					close(new_fd); //si une connexion arrive alors que le programme est terminé, on sort
					return;
				}
				char answer[MAXRECVDATA];
				/*sprintf(answer,"Serveur %s.\n", srv.name);
				if (send(new_fd, answer, strlen(answer), 0) == -1)
				perror("send");*/

				srv.recvdata = (msg*) malloc (sizeof (msg));
				char recvdata[MAXRECVDATA];
				bzero(srv.recvdata,sizeof (msg));
				if ((srv.numbytes=recv(new_fd, recvdata, MAXRECVDATA, 0)) == -1) {
					perror("recv");
					log_srv(&srv,"erreur lors du recv!");
					exit(1);
				}
				srv.recvdata = str_to_msg(recvdata);
				sprintf(tmp,"%d octets reçu par %s %s:%d",srv.numbytes,srv.name, inet_ntoa(srv.remote_addr.sin_addr),srv.remote_addr.sin_port);
				log_msg(tmp,srv.recvdata);
				char idbourse_str[5]; // identifiant de la bourse
				int idbourse;
				//process_msg(srv.recvdata,rtn);
				strncpy(idbourse_str,srv.recvdata->action,4); // on copie l'id de la bourse du message
				idbourse_str[4]='\0';idbourse = atoi(idbourse_str);
				if(idbourse==mdl->bourse_id) {
					msg * rtn = (msg*) malloc(sizeof(msg)); // message retourné par process_msg
					rtn = execution_msg(srv.recvdata, &stock_restant, &(*act), nombre_actions);
					log_msg("message retournée en local:",rtn);
					char* rtnstr = msg_to_str(rtn);
					if (send(new_fd, rtnstr, strlen(rtnstr), 0) == -1)
					perror("send");
				} else {
					sprintf(tmp,"ATTENTION: réception d'un message d'une autre bourse: me=%d; him=%d",mdl->bourse_id,idbourse);
					log_srv(&srv,tmp);
				}
				close(new_fd); // on ferme la connexion une fois le message reçu
			}
			close(new_fd); // le parent n'a pas besoin de new_fd

			while(waitpid(-1,NULL,WNOHANG) > 0); // nettoyage des processus fils

		} // fin while du "accept"
	}
}

msg* execution_msg(msg *mess, int *stock_restant, action *act,
		int nombre_actions) {
	return execution(mess->emetteur, mess->type, mess->action, mess->valeur,
			stock_restant, act, nombre_actions);
}

msg* execution(char* emetteur, char* type_transaction, char* id_action_ordre,
		char* quantite_ordre, int *stock_restant_p, action *act_p,
		int nombre_actions) {

	int stock_restant = *stock_restant_p;
	action act = *act_p;
	char valeur_totale_transaction[6], id_action[12], valeur_action[6],
			stock_action[100], type_action[12];

	int i, trouve=0;
	//On récupère id_action, valeur_action et stock_action depuis le tableau
	for (i=0; i<nombre_actions; i++) {
		if (strcmp(act.id[i], id_action_ordre)==0) {
			trouve=1;
			strcpy(id_action, act.id[i]);
			strcpy(valeur_action, act.val[i]);
			strcpy(stock_action, act.stock[i]);
		}
	}
	if (trouve==0) {
		log_smth("ERREUR: l'action envoyé n'a pas été trouvée!");
		exit(1);
	}
	strcpy(valeur_totale_transaction, "0");

	//ACHAT
	if (strcmp(type_transaction, "Achat")==0) {

		//On compare le nombres d'actions demandées et le stock
		//Si le prix d'achat a pu etre calculé:  envoi de l'accusé positif, maj du stock
		//Calcul du prix d'achat

		sprintf(valeur_totale_transaction, "%.2lf", PrixAchat(strtod(
				valeur_action, NULL), atoi(stock_action), atoi(quantite_ordre)));

		if (atoi(valeur_totale_transaction)!=-1) {
			//maj du stock
			stock_restant += atoi(quantite_ordre);
			sprintf(stock_action, "%d", atoi(stock_action)
					- atoi(quantite_ordre));
		} else { //Si le prix d'achat retourne erreur: envoi de l'accusé négatif
			strcpy(valeur_totale_transaction, "0");
		}
		//VENTE
	} else if (strcmp(type_transaction, "Vente")==0) {
		//On vérifie qu'il reste suffisamment de place de stockage
		//Si place suffisante: calcul du prix de vente, envoi de l'accusé positif,maj du stock
		sprintf(valeur_totale_transaction, "%.2lf", PrixVente(strtod(
				valeur_action, NULL), atoi(stock_action), atoi(quantite_ordre)));

		if (stock_restant>=atoi(quantite_ordre)
				&& atoi(valeur_totale_transaction)!=-1) {
			//maj du stock
			stock_restant -= atoi(quantite_ordre);
			sprintf(stock_action, "%d", atoi(stock_action)
					+ atoi(quantite_ordre));
		} else { //Si le stock est inférieur ou prix d'achat retourne erreur: envoi de l'accusé négatif
			strcpy(valeur_totale_transaction, "0");
		}
	} else {
		log_smth("erreur: le serveur d'exécution n'est pas censé recevoir d'accusé");
		exit(1);
	}
	sprintf(type_action, "Accuse%s", type_transaction); // on est déjà sorti si il y a eu erreur
	//envoi de l'accusé positif
	msg* accuse = create_msg(emetteur, type_action, id_action,
			valeur_totale_transaction);
	log_msg("test d'accusé", accuse);
	log_smth("espace dispo:%d", stock_restant);
	log_smth("stock de l'action:%s", stock_action);
	*stock_restant_p = stock_restant;

	//TODO: gérer le pb de maj des stocks


	for (i=0; i<nombre_actions; i++) {
		if (strcmp(act.id[i], id_action_ordre)==0) {
			strcpy(act.stock[i], stock_action);
		}
	}
	*act_p = act;

	return accuse;
}
